package org.xiyinjihe.platform.service.base;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.entity.Example;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by AnthonyPark on 2019/3/6.
 */
public abstract class AbstractService<T> implements BaseService<T> {

    @Autowired
    protected Mapper<T> baseMapper;

    private Class<?> clazz = null;

    private ThreadLocal<Page> pageThreadLocal = new ThreadLocal<>();

    protected Class<?> getEntityClass() {
        if (clazz == null) {
            clazz = (Class<?>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return clazz;
    }

    @Override
    public int insert(T entity) {
        return baseMapper.insert(entity);
    }

    @Override
    public int insertSelective(T entity) {
        return baseMapper.insertSelective(entity);
    }

    @Override
    public int updateByPrimaryKey(T entity) {
        return baseMapper.updateByPrimaryKey(entity);
    }

    @Override
    public int updateByPrimaryKeySelective(T entity) {
        return baseMapper.updateByPrimaryKeySelective(entity);
    }

    @Override
    public int updateByExampleSelective(T entity,T where){
        if(null == entity && null == where){
            return 0;
        }

        Map<String, Object> map = getFieldValueMap(where);
        Example example = new Example(getEntityClass());
        Example.Criteria criteria = example.createCriteria();
        for(Map.Entry<String, Object> entry : map.entrySet()){
            criteria.andEqualTo(entry.getKey(), entry.getValue());
        }
        return baseMapper.updateByExampleSelective(entity,example);
    }

    @Override
    public int deleteByPrimaryKey(Object primaryKey) {
        return baseMapper.deleteByPrimaryKey(primaryKey);
    }

    @Override
    public int deleteByPrimaryKeys(List<Object> primaryKeys) {
        int resulrt = 0;
        for (Object primaryKey : primaryKeys) {
            resulrt += baseMapper.deleteByPrimaryKey(primaryKey);
        }
        return resulrt;
    }

    @Override
    public int deleteByField(String field, String value) {
        return deleteByFields(new String[] { field }, new String[] { value });
    }

    @Override
    public int deleteByFields(String[] fields, String[] values) {
        if (null == fields || null == values || fields.length == 0 || fields.length != values.length) {
            return 0;
        }
        Example example = new Example(getEntityClass());
        Example.Criteria criteria = example.createCriteria();
        for (int i = 0; i < fields.length; i++) {
            criteria.andEqualTo(fields[i], values[i]);
        }
        return baseMapper.deleteByExample(example);
    }

    @Override
    public T selectOne(T entity) {
        return baseMapper.selectOne(entity);
    }

    @Override
    public T selectByPrimaryKey(Object primaryKey) {
        return baseMapper.selectByPrimaryKey(primaryKey);
    }

    @Override
    public List<T> selectPage(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return baseMapper.selectAll();
    }


    @Override
    public List<T> selectByFields(T entity, int pageNum, int pageSize) {
        if (entity == null) {
            return null;
        }
        Map<String, Object> map = getFieldValueMap(entity);
        Example example = new Example(getEntityClass());
        for(Map.Entry<String, Object> entry : map.entrySet()){
            String keyword = "%"+entry.getValue()+"%";
            example.or().andLike(entry.getKey(), keyword);
        }

        /*for (int i = 0; i < fields.length; i++) {
            String keyword = "%"+values[i]+"%";
            example.or().andLike(fields[i], keyword);
        }*/
        PageHelper.startPage(pageNum, pageSize);
        return baseMapper.selectByExample(example);
    }



    @Override
    public List<T> selectByEqFields(T entity, int pageNum, int pageSize) {
        return selectByEqFieldsOrderBy(entity, pageNum, pageSize, null);
    }

    @Override
    public List<T> selectByEqFieldsOrderBy(T entity, int pageNum, int pageSize,String orderBy) {
        if (entity == null) {
            return null;
        }
        Map<String, Object> map = getFieldValueMap(entity);
        Example example = new Example(getEntityClass());
        Example.Criteria criteria = example.createCriteria();
        for(Map.Entry<String, Object> entry : map.entrySet()){
            criteria.andEqualTo(entry.getKey(), entry.getValue());
        }
        if(pageNum > 0 && pageSize > 0){
            Page page = PageHelper.startPage(pageNum, pageSize);
            pageThreadLocal.set(page);
        }
        if(StringUtils.hasText(orderBy)){
            PageHelper.orderBy(orderBy);
        }
        return baseMapper.selectByExample(example);
    }

    @Override
    public int selectCountByFields(T entity){
        return baseMapper.selectCount(entity);
    }

    @Override
    public Page getPageInfo(){
        return pageThreadLocal.get();
    }

    /**
     * 获取指定实例的所有属性名及对应值的Map实例
     *
     * @param entity
     *            实例
     * @return 字段名及对应值的Map实例
     */
    protected Map<String, Object> getFieldValueMap(T entity) {
        // key是属性名，value是对应值
        Map<String, Object> fieldValueMap = new HashMap<String, Object>();

        // 获取当前加载的实体类中所有属性（字段）
        Field[] fields = getEntityClass().getDeclaredFields();

        for (int i = 0; i < fields.length; i++) {
            Field f = fields[i];
            String key = f.getName();// 属性名
            Object value = null;//属性值
            if (! "serialVersionUID".equals(key)) {// 忽略序列化版本ID号
                f.setAccessible(true);// 取消Java语言访问检查
                try {
                    value =f.get(entity);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                if(value != null){
                    fieldValueMap.put(key, value);
                }
            }
        }
        return fieldValueMap;
    }

}
